// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#![allow(dead_code)]
#![allow(unused_imports)]

use crate::ipc::gen::Schema::*;
use crate::ipc::gen::SparseTensor::*;
use crate::ipc::gen::Tensor::*;
use flatbuffers::EndianScalar;
use std::{cmp::Ordering, mem};
// automatically generated by the FlatBuffers compiler, do not modify

/// ----------------------------------------------------------------------
/// The root Message type
/// This union enables us to easily send different message types without
/// redundant storage, and in the future we can easily add new message types.
///
/// Arrow implementations do not need to implement all of the message types,
/// which may include experimental metadata types. For maximum compatibility,
/// it is best to send data using RecordBatch
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum MessageHeader {
    NONE = 0,
    Schema = 1,
    DictionaryBatch = 2,
    RecordBatch = 3,
    Tensor = 4,
    SparseTensor = 5,
}

const ENUM_MIN_MESSAGE_HEADER: u8 = 0;
const ENUM_MAX_MESSAGE_HEADER: u8 = 5;

impl<'a> flatbuffers::Follow<'a> for MessageHeader {
    type Inner = Self;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        flatbuffers::read_scalar_at::<Self>(buf, loc)
    }
}

impl flatbuffers::EndianScalar for MessageHeader {
    #[inline]
    fn to_little_endian(self) -> Self {
        let n = u8::to_le(self as u8);
        let p = &n as *const u8 as *const MessageHeader;
        unsafe { *p }
    }
    #[inline]
    fn from_little_endian(self) -> Self {
        let n = u8::from_le(self as u8);
        let p = &n as *const u8 as *const MessageHeader;
        unsafe { *p }
    }
}

impl flatbuffers::Push for MessageHeader {
    type Output = MessageHeader;
    #[inline]
    fn push(&self, dst: &mut [u8], _rest: &[u8]) {
        flatbuffers::emplace_scalar::<MessageHeader>(dst, *self);
    }
}

#[allow(non_camel_case_types)]
const ENUM_VALUES_MESSAGE_HEADER: [MessageHeader; 6] = [
    MessageHeader::NONE,
    MessageHeader::Schema,
    MessageHeader::DictionaryBatch,
    MessageHeader::RecordBatch,
    MessageHeader::Tensor,
    MessageHeader::SparseTensor,
];

#[allow(non_camel_case_types)]
const ENUM_NAMES_MESSAGE_HEADER: [&'static str; 6] = [
    "NONE",
    "Schema",
    "DictionaryBatch",
    "RecordBatch",
    "Tensor",
    "SparseTensor",
];

pub fn enum_name_message_header(e: MessageHeader) -> &'static str {
    let index = e as u8;
    ENUM_NAMES_MESSAGE_HEADER[index as usize]
}

pub struct MessageHeaderUnionTableOffset {}
/// ----------------------------------------------------------------------
/// Data structures for describing a table row batch (a collection of
/// equal-length Arrow arrays)
/// Metadata about a field at some level of a nested type tree (but not
/// its children).
///
/// For example, a List<Int16> with values [[1, 2, 3], null, [4], [5, 6], null]
/// would have {length: 5, null_count: 2} for its List node, and {length: 6,
/// null_count: 0} for its Int16 node, as separate FieldNode structs
// struct FieldNode, aligned to 8
#[repr(C, align(8))]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldNode {
    length_: i64,
    null_count_: i64,
} // pub struct FieldNode
impl flatbuffers::SafeSliceAccess for FieldNode {}
impl<'a> flatbuffers::Follow<'a> for FieldNode {
    type Inner = &'a FieldNode;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        <&'a FieldNode>::follow(buf, loc)
    }
}
impl<'a> flatbuffers::Follow<'a> for &'a FieldNode {
    type Inner = &'a FieldNode;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        flatbuffers::follow_cast_ref::<FieldNode>(buf, loc)
    }
}
impl<'b> flatbuffers::Push for FieldNode {
    type Output = FieldNode;
    #[inline]
    fn push(&self, dst: &mut [u8], _rest: &[u8]) {
        let src = unsafe {
            std::slice::from_raw_parts(
                self as *const FieldNode as *const u8,
                Self::size(),
            )
        };
        dst.copy_from_slice(src);
    }
}
impl<'b> flatbuffers::Push for &'b FieldNode {
    type Output = FieldNode;

    #[inline]
    fn push(&self, dst: &mut [u8], _rest: &[u8]) {
        let src = unsafe {
            std::slice::from_raw_parts(
                *self as *const FieldNode as *const u8,
                Self::size(),
            )
        };
        dst.copy_from_slice(src);
    }
}

impl FieldNode {
    pub fn new<'a>(_length: i64, _null_count: i64) -> Self {
        FieldNode {
            length_: _length.to_little_endian(),
            null_count_: _null_count.to_little_endian(),
        }
    }
    /// The number of value slots in the Arrow array at this level of a nested
    /// tree
    pub fn length<'a>(&'a self) -> i64 {
        self.length_.from_little_endian()
    }
    /// The number of observed nulls. Fields with null_count == 0 may choose not
    /// to write their physical validity bitmap out as a materialized buffer,
    /// instead setting the length of the bitmap buffer to 0.
    pub fn null_count<'a>(&'a self) -> i64 {
        self.null_count_.from_little_endian()
    }
}

pub enum RecordBatchOffset {}
#[derive(Copy, Clone, Debug, PartialEq)]

/// A data header describing the shared memory layout of a "record" or "row"
/// batch. Some systems call this a "row batch" internally and others a "record
/// batch".
pub struct RecordBatch<'a> {
    pub _tab: flatbuffers::Table<'a>,
}

impl<'a> flatbuffers::Follow<'a> for RecordBatch<'a> {
    type Inner = RecordBatch<'a>;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        Self {
            _tab: flatbuffers::Table { buf: buf, loc: loc },
        }
    }
}

impl<'a> RecordBatch<'a> {
    #[inline]
    pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
        RecordBatch { _tab: table }
    }
    #[allow(unused_mut)]
    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
        _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
        args: &'args RecordBatchArgs<'args>,
    ) -> flatbuffers::WIPOffset<RecordBatch<'bldr>> {
        let mut builder = RecordBatchBuilder::new(_fbb);
        builder.add_length(args.length);
        if let Some(x) = args.buffers {
            builder.add_buffers(x);
        }
        if let Some(x) = args.nodes {
            builder.add_nodes(x);
        }
        builder.finish()
    }

    pub const VT_LENGTH: flatbuffers::VOffsetT = 4;
    pub const VT_NODES: flatbuffers::VOffsetT = 6;
    pub const VT_BUFFERS: flatbuffers::VOffsetT = 8;

    /// number of records / rows. The arrays in the batch should all have this
    /// length
    #[inline]
    pub fn length(&self) -> i64 {
        self._tab
            .get::<i64>(RecordBatch::VT_LENGTH, Some(0))
            .unwrap()
    }
    /// Nodes correspond to the pre-ordered flattened logical schema
    #[inline]
    pub fn nodes(&self) -> Option<&'a [FieldNode]> {
        self._tab
            .get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<FieldNode>>>(
                RecordBatch::VT_NODES,
                None,
            )
            .map(|v| v.safe_slice())
    }
    /// Buffers correspond to the pre-ordered flattened buffer tree
    ///
    /// The number of buffers appended to this list depends on the schema. For
    /// example, most primitive arrays will have 2 buffers, 1 for the validity
    /// bitmap and 1 for the values. For struct arrays, there will only be a
    /// single buffer for the validity (nulls) bitmap
    #[inline]
    pub fn buffers(&self) -> Option<&'a [Buffer]> {
        self._tab
            .get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Buffer>>>(
                RecordBatch::VT_BUFFERS,
                None,
            )
            .map(|v| v.safe_slice())
    }
}

pub struct RecordBatchArgs<'a> {
    pub length: i64,
    pub nodes: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, FieldNode>>>,
    pub buffers: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, Buffer>>>,
}
impl<'a> Default for RecordBatchArgs<'a> {
    #[inline]
    fn default() -> Self {
        RecordBatchArgs {
            length: 0,
            nodes: None,
            buffers: None,
        }
    }
}
pub struct RecordBatchBuilder<'a: 'b, 'b> {
    fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> RecordBatchBuilder<'a, 'b> {
    #[inline]
    pub fn add_length(&mut self, length: i64) {
        self.fbb_
            .push_slot::<i64>(RecordBatch::VT_LENGTH, length, 0);
    }
    #[inline]
    pub fn add_nodes(
        &mut self,
        nodes: flatbuffers::WIPOffset<flatbuffers::Vector<'b, FieldNode>>,
    ) {
        self.fbb_
            .push_slot_always::<flatbuffers::WIPOffset<_>>(RecordBatch::VT_NODES, nodes);
    }
    #[inline]
    pub fn add_buffers(
        &mut self,
        buffers: flatbuffers::WIPOffset<flatbuffers::Vector<'b, Buffer>>,
    ) {
        self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(
            RecordBatch::VT_BUFFERS,
            buffers,
        );
    }
    #[inline]
    pub fn new(
        _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    ) -> RecordBatchBuilder<'a, 'b> {
        let start = _fbb.start_table();
        RecordBatchBuilder {
            fbb_: _fbb,
            start_: start,
        }
    }
    #[inline]
    pub fn finish(self) -> flatbuffers::WIPOffset<RecordBatch<'a>> {
        let o = self.fbb_.end_table(self.start_);
        flatbuffers::WIPOffset::new(o.value())
    }
}

pub enum DictionaryBatchOffset {}
#[derive(Copy, Clone, Debug, PartialEq)]

/// For sending dictionary encoding information. Any Field can be
/// dictionary-encoded, but in this case none of its children may be
/// dictionary-encoded.
/// There is one vector / column per dictionary, but that vector / column
/// may be spread across multiple dictionary batches by using the isDelta
/// flag
pub struct DictionaryBatch<'a> {
    pub _tab: flatbuffers::Table<'a>,
}

impl<'a> flatbuffers::Follow<'a> for DictionaryBatch<'a> {
    type Inner = DictionaryBatch<'a>;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        Self {
            _tab: flatbuffers::Table { buf: buf, loc: loc },
        }
    }
}

impl<'a> DictionaryBatch<'a> {
    #[inline]
    pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
        DictionaryBatch { _tab: table }
    }
    #[allow(unused_mut)]
    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
        _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
        args: &'args DictionaryBatchArgs<'args>,
    ) -> flatbuffers::WIPOffset<DictionaryBatch<'bldr>> {
        let mut builder = DictionaryBatchBuilder::new(_fbb);
        builder.add_id(args.id);
        if let Some(x) = args.data {
            builder.add_data(x);
        }
        builder.add_isDelta(args.isDelta);
        builder.finish()
    }

    pub const VT_ID: flatbuffers::VOffsetT = 4;
    pub const VT_DATA: flatbuffers::VOffsetT = 6;
    pub const VT_ISDELTA: flatbuffers::VOffsetT = 8;

    #[inline]
    pub fn id(&self) -> i64 {
        self._tab
            .get::<i64>(DictionaryBatch::VT_ID, Some(0))
            .unwrap()
    }
    #[inline]
    pub fn data(&self) -> Option<RecordBatch<'a>> {
        self._tab
            .get::<flatbuffers::ForwardsUOffset<RecordBatch<'a>>>(
                DictionaryBatch::VT_DATA,
                None,
            )
    }
    /// If isDelta is true the values in the dictionary are to be appended to a
    /// dictionary with the indicated id. If isDelta is false this dictionary
    /// should replace the existing dictionary.
    #[inline]
    pub fn isDelta(&self) -> bool {
        self._tab
            .get::<bool>(DictionaryBatch::VT_ISDELTA, Some(false))
            .unwrap()
    }
}

pub struct DictionaryBatchArgs<'a> {
    pub id: i64,
    pub data: Option<flatbuffers::WIPOffset<RecordBatch<'a>>>,
    pub isDelta: bool,
}
impl<'a> Default for DictionaryBatchArgs<'a> {
    #[inline]
    fn default() -> Self {
        DictionaryBatchArgs {
            id: 0,
            data: None,
            isDelta: false,
        }
    }
}
pub struct DictionaryBatchBuilder<'a: 'b, 'b> {
    fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> DictionaryBatchBuilder<'a, 'b> {
    #[inline]
    pub fn add_id(&mut self, id: i64) {
        self.fbb_.push_slot::<i64>(DictionaryBatch::VT_ID, id, 0);
    }
    #[inline]
    pub fn add_data(&mut self, data: flatbuffers::WIPOffset<RecordBatch<'b>>) {
        self.fbb_
            .push_slot_always::<flatbuffers::WIPOffset<RecordBatch>>(
                DictionaryBatch::VT_DATA,
                data,
            );
    }
    #[inline]
    pub fn add_isDelta(&mut self, isDelta: bool) {
        self.fbb_
            .push_slot::<bool>(DictionaryBatch::VT_ISDELTA, isDelta, false);
    }
    #[inline]
    pub fn new(
        _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    ) -> DictionaryBatchBuilder<'a, 'b> {
        let start = _fbb.start_table();
        DictionaryBatchBuilder {
            fbb_: _fbb,
            start_: start,
        }
    }
    #[inline]
    pub fn finish(self) -> flatbuffers::WIPOffset<DictionaryBatch<'a>> {
        let o = self.fbb_.end_table(self.start_);
        flatbuffers::WIPOffset::new(o.value())
    }
}

pub enum MessageOffset {}
#[derive(Copy, Clone, Debug, PartialEq)]

pub struct Message<'a> {
    pub _tab: flatbuffers::Table<'a>,
}

impl<'a> flatbuffers::Follow<'a> for Message<'a> {
    type Inner = Message<'a>;
    #[inline]
    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
        Self {
            _tab: flatbuffers::Table { buf: buf, loc: loc },
        }
    }
}

impl<'a> Message<'a> {
    #[inline]
    pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
        Message { _tab: table }
    }
    #[allow(unused_mut)]
    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
        _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
        args: &'args MessageArgs<'args>,
    ) -> flatbuffers::WIPOffset<Message<'bldr>> {
        let mut builder = MessageBuilder::new(_fbb);
        builder.add_bodyLength(args.bodyLength);
        if let Some(x) = args.custom_metadata {
            builder.add_custom_metadata(x);
        }
        if let Some(x) = args.header {
            builder.add_header(x);
        }
        builder.add_version(args.version);
        builder.add_header_type(args.header_type);
        builder.finish()
    }

    pub const VT_VERSION: flatbuffers::VOffsetT = 4;
    pub const VT_HEADER_TYPE: flatbuffers::VOffsetT = 6;
    pub const VT_HEADER: flatbuffers::VOffsetT = 8;
    pub const VT_BODYLENGTH: flatbuffers::VOffsetT = 10;
    pub const VT_CUSTOM_METADATA: flatbuffers::VOffsetT = 12;

    #[inline]
    pub fn version(&self) -> MetadataVersion {
        self._tab
            .get::<MetadataVersion>(Message::VT_VERSION, Some(MetadataVersion::V1))
            .unwrap()
    }
    #[inline]
    pub fn header_type(&self) -> MessageHeader {
        self._tab
            .get::<MessageHeader>(Message::VT_HEADER_TYPE, Some(MessageHeader::NONE))
            .unwrap()
    }
    #[inline]
    pub fn header(&self) -> Option<flatbuffers::Table<'a>> {
        self._tab
            .get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(
                Message::VT_HEADER,
                None,
            )
    }
    #[inline]
    pub fn bodyLength(&self) -> i64 {
        self._tab
            .get::<i64>(Message::VT_BODYLENGTH, Some(0))
            .unwrap()
    }
    #[inline]
    pub fn custom_metadata(
        &self,
    ) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<KeyValue<'a>>>> {
        self._tab.get::<flatbuffers::ForwardsUOffset<
            flatbuffers::Vector<flatbuffers::ForwardsUOffset<KeyValue<'a>>>,
        >>(Message::VT_CUSTOM_METADATA, None)
    }
    #[inline]
    #[allow(non_snake_case)]
    pub fn header_as_schema(&self) -> Option<Schema<'a>> {
        if self.header_type() == MessageHeader::Schema {
            self.header().map(|u| Schema::init_from_table(u))
        } else {
            None
        }
    }

    #[inline]
    #[allow(non_snake_case)]
    pub fn header_as_dictionary_batch(&self) -> Option<DictionaryBatch<'a>> {
        if self.header_type() == MessageHeader::DictionaryBatch {
            self.header().map(|u| DictionaryBatch::init_from_table(u))
        } else {
            None
        }
    }

    #[inline]
    #[allow(non_snake_case)]
    pub fn header_as_record_batch(&self) -> Option<RecordBatch<'a>> {
        if self.header_type() == MessageHeader::RecordBatch {
            self.header().map(|u| RecordBatch::init_from_table(u))
        } else {
            None
        }
    }

    #[inline]
    #[allow(non_snake_case)]
    pub fn header_as_tensor(&self) -> Option<Tensor<'a>> {
        if self.header_type() == MessageHeader::Tensor {
            self.header().map(|u| Tensor::init_from_table(u))
        } else {
            None
        }
    }

    #[inline]
    #[allow(non_snake_case)]
    pub fn header_as_sparse_tensor(&self) -> Option<SparseTensor<'a>> {
        if self.header_type() == MessageHeader::SparseTensor {
            self.header().map(|u| SparseTensor::init_from_table(u))
        } else {
            None
        }
    }
}

pub struct MessageArgs<'a> {
    pub version: MetadataVersion,
    pub header_type: MessageHeader,
    pub header: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
    pub bodyLength: i64,
    pub custom_metadata: Option<
        flatbuffers::WIPOffset<
            flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<KeyValue<'a>>>,
        >,
    >,
}
impl<'a> Default for MessageArgs<'a> {
    #[inline]
    fn default() -> Self {
        MessageArgs {
            version: MetadataVersion::V1,
            header_type: MessageHeader::NONE,
            header: None,
            bodyLength: 0,
            custom_metadata: None,
        }
    }
}
pub struct MessageBuilder<'a: 'b, 'b> {
    fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> MessageBuilder<'a, 'b> {
    #[inline]
    pub fn add_version(&mut self, version: MetadataVersion) {
        self.fbb_.push_slot::<MetadataVersion>(
            Message::VT_VERSION,
            version,
            MetadataVersion::V1,
        );
    }
    #[inline]
    pub fn add_header_type(&mut self, header_type: MessageHeader) {
        self.fbb_.push_slot::<MessageHeader>(
            Message::VT_HEADER_TYPE,
            header_type,
            MessageHeader::NONE,
        );
    }
    #[inline]
    pub fn add_header(
        &mut self,
        header: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>,
    ) {
        self.fbb_
            .push_slot_always::<flatbuffers::WIPOffset<_>>(Message::VT_HEADER, header);
    }
    #[inline]
    pub fn add_bodyLength(&mut self, bodyLength: i64) {
        self.fbb_
            .push_slot::<i64>(Message::VT_BODYLENGTH, bodyLength, 0);
    }
    #[inline]
    pub fn add_custom_metadata(
        &mut self,
        custom_metadata: flatbuffers::WIPOffset<
            flatbuffers::Vector<'b, flatbuffers::ForwardsUOffset<KeyValue<'b>>>,
        >,
    ) {
        self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(
            Message::VT_CUSTOM_METADATA,
            custom_metadata,
        );
    }
    #[inline]
    pub fn new(
        _fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    ) -> MessageBuilder<'a, 'b> {
        let start = _fbb.start_table();
        MessageBuilder {
            fbb_: _fbb,
            start_: start,
        }
    }
    #[inline]
    pub fn finish(self) -> flatbuffers::WIPOffset<Message<'a>> {
        let o = self.fbb_.end_table(self.start_);
        flatbuffers::WIPOffset::new(o.value())
    }
}

#[inline]
pub fn get_root_as_message<'a>(buf: &'a [u8]) -> Message<'a> {
    flatbuffers::get_root::<Message<'a>>(buf)
}

#[inline]
pub fn get_size_prefixed_root_as_message<'a>(buf: &'a [u8]) -> Message<'a> {
    flatbuffers::get_size_prefixed_root::<Message<'a>>(buf)
}

#[inline]
pub fn finish_message_buffer<'a, 'b>(
    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    root: flatbuffers::WIPOffset<Message<'a>>,
) {
    fbb.finish(root, None);
}

#[inline]
pub fn finish_size_prefixed_message_buffer<'a, 'b>(
    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
    root: flatbuffers::WIPOffset<Message<'a>>,
) {
    fbb.finish_size_prefixed(root, None);
}
